package macrotools;
import haxe.macro.Context;
import haxe.macro.Expr;
import haxe.macro.Type;
import haxe.macro.Expr;

class TypeTools 
{
	public static function path(type:Type):Null<String>
	{
		if (type == null)
			return null;
		
		return switch(type)
		{
			case TMono( t ):
				var t2 = t.get();
				path(t2);
			case TEnum( t, _ ): t.toString();
			case TInst( t, _ ): t.toString();
			case TType( t, _ ): t.toString();
			case TFun(_, _), TAnonymous(_), TDynamic(_): null;
#if haxe_209
			case TLazy( f ): path(f());
#end
		}
	}
	
	public static function getComplexType(ctypeSignature:String):ComplexType
	{
		var pos = Context.makePosition( { min:0, max:0, file:"Complex Type Conversion" } );
		return switch(Context.parse("{var _:" + ctypeSignature + ";}", pos).expr)
		{
			case EBlock(block):
				switch(block[0].expr)
				{
					case EVars(v):
						v[0].type;
					default: throw "assert";
				}
			default: throw "assert";
		};
	}
	
	public static function getType(complex:ComplexType, pos:Position):Type 
	{
		var v = {expr:EVars([{name:"_", type:complex, expr:null}]), pos:pos};
		return Context.typeof({expr:EBlock([v, {expr:EConst(CIdent("_")), pos:pos}]), pos:pos});
	}
	
	public static function args(args:Array<Type>):String 
	{
		if (args.length > 0)
		{
			return "<" + Lambda.map(args, toString).join(", ") + ">";
		} else {
			return "";
		}
	}
	
	public static function toString(type:Type):Null<String> 
	{
		if (type == null)
			return null;
		
		return switch(type)
		{
			case TMono( t ):
				var t2 = t.get();
				toString(t2);
			case TEnum( t, params ): t.toString() + args(params);
			case TInst( t, params ): t.toString() + args(params);
			case TType( t, params ): t.toString() + args(params);
			case TFun( args, ret ): 
				if (args.length == 0)
					"Void->" + toString(ret);
				else
					Lambda.map(args, function(arg) return toString(arg.t)).join("->") + "->" + toString(ret);
			case TAnonymous( a ):
				var sbuf = new StringBuf();
				sbuf.add("{ ");
				var first = true;
				for (a in a.get().fields)
				{
					if (first) first = false; else sbuf.add(", ");
					sbuf.add(a.name);
					sbuf.add(" : ");
					sbuf.add(toString(a.type));
				}
				sbuf.add(" }");
				
				sbuf.toString();
			case TDynamic( t ):
				if (t != null)
					"Dynamic<" + toString(t) + ">";
				else
					"Dynamic";
#if haxe_209
			case TLazy( f ): toString(f());
#end
	}
}
}